﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xml;
using SpringBeansEditor.Editors;
using SpringBeansEditor.Providers;
using SpringBeansEditor.GUIHelpers;
using SpringBeansEditor.Commands;

namespace SpringBeansEditor
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        Dictionary<string, List<GUICommand>> NodeCommands;
        Dictionary<string, IEditor> NodeEditors;
        IEditor _curr_editor;
        XmlDataProvider _dataxml;
        TypesProvider _reflection_provider;

        public MainWindow()
        {
            InitializeComponent();
            _dataxml = this.FindResource("dataxml") as XmlDataProvider;

            NodeEditors = new Dictionary<string, IEditor>();
            NodeEditors.Add("object", BeanEditorForm);
            BeanEditorForm.OnBeanChanged = OnBeanChanged;
            NodeEditors.Add("property", PropertyEditorForm);
            NodeCommands = new Dictionary<string, List<GUICommand>>();

            InitializeCommands();

            HideAllEditors();
            HideAllCommands();

            _reflection_provider = TypesProvider.GetInstance();
            _reflection_provider.OnAssembliesLoaded = LoadAssemblies;

            LoadXMLForm.DataXml = _dataxml;
        }

        private void InitializeCommands()
        {
            AddObjectCommand add_cmd = new AddObjectCommand();
            add_cmd.OnExecute += OnObjectCommandExecuted;
            AddCommand("objects", add_cmd);

            RemoveObjectCommand rem_cmd = new RemoveObjectCommand();
            rem_cmd.OnExecute += OnObjectCommandExecuted;
            AddCommand("object", rem_cmd);

            AddCommand("object", new AddPropertyCommand());
            AddCommand("property", new AddPropertyCommand());

            AddCommand("property", new RemovePropertyCommand());
        }

        /// <summary>
        /// Registers a command usable in the passed node name.
        /// </summary>
        /// <param name="node_name"></param>
        /// <param name="new_command"></param>
        private void AddCommand(string node_name, IXmlCommand new_command)
        {
            if (!NodeCommands.ContainsKey(node_name))
            {
                NodeCommands.Add(node_name, new List<GUICommand>());
            }
            GUICommand command_gui = new GUICommand(new_command);
            //Add command to command list
            NodeCommands[node_name].Add(command_gui);
            //Add the command to the panel
            CommandsPanel.Children.Add(command_gui);
        }

        private void HideAllEditors()
        {
            foreach (var editor in NodeEditors.Values)
            {
                editor.Hide();
            }
        }

        private void HideAllCommands()
        {
            foreach (var command_guis in NodeCommands.Values)
            {
                foreach (var command_gui in command_guis)
                {
                    command_gui.Hide();
                }
            }
        }

        private void treeview_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            XmlElement selected = e.NewValue as XmlElement;
            if (selected != null)
            {
                string element_selected_name = selected.Name.ToLowerInvariant();
                
                //Show the editor available for this type of node
                if (NodeEditors.ContainsKey(element_selected_name))
                {
                    if (_curr_editor != null)
                        _curr_editor.Hide();
                    _curr_editor = NodeEditors[element_selected_name];
                    _curr_editor.Show();
                    _curr_editor.ShowXMLElement(selected);
                }
                //Show the commands available for this type of node
                HideAllCommands();
                if (NodeCommands.ContainsKey(element_selected_name))
                {
                    foreach (var command_gui in NodeCommands[element_selected_name])
                    {
                        command_gui.Show();
                        command_gui.SetCurrXMLNode(_dataxml.Document, selected);
                    }
                }
            }
        }


        void LoadAssemblies()
        {
            foreach (var editor in NodeEditors.Values)
            {
                editor.OnAssemblyUpdated(_reflection_provider);
            }
        }


        private void OnBeanChanged()
        {
            foreach (var editor in NodeEditors.Values)
            {
                editor.OnXmlUpdated(_dataxml.Document);
            }
        }

        private void XmlDataProvider_DataChanged(object sender, EventArgs e)
        {
            //Update global register of types and objects
            TypesProvider reflection_provider = TypesProvider.GetInstance();
            reflection_provider.AddTypesUsed(_dataxml.Document) ;

            OnBeanChanged();
        }

        private void OnObjectCommandExecuted(IXmlCommand cmd)
        {
            OnBeanChanged();
        }

        private void AssemblyLoader_Loaded(object sender, RoutedEventArgs e)
        {

        }
    }
}
